/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is COID coidgen tool.
 *
 * The Initial Developer of the Original Code is
 * PosAm.
 * Portions created by the Initial Developer are Copyright (C) 2003
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Robo Strycek
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */


#include "os.h"



char TEMPL_DISPATCH_CPP[] =
"#include \"%service_header_name%\"" EOL
"#include \"coid/comm/metastream/metastream.h\"" EOL
"" EOL
"" EOL
"namespace %namespace% {" EOL
"" EOL
"" EOL
"static inline const char ** COID_OUT_ARGS(const char ** from) {" EOL
"	while( *from ) from++;" EOL
"	return ++from;" EOL
"}" EOL
"" EOL
"typedef ServiceDescriptor::MethodDesc MethodDesc;" EOL
"#define COID_MethodDesc_constructor(S,I,F)         MethodDesc( S[0], S[1], &S[2], COID_OUT_ARGS(&S[2]), I, F )" EOL
"#define COID_MethodDesc_constructor_NotImpl        MethodDesc( NULL, NULL, NULL, NULL, 0, 0 )" EOL
"" EOL
"" EOL
"" EOL
"typedef void (%name%::*coid_fnc)();" EOL
"" EOL
"%coid_throw_function%"
EOL
"/// we need type cast in case there are 2 or more methods with the same name" EOL
"#define COID_DISPATCH_CREATE_HOOK(M,i,t,tc) \\" EOL
"	if( i < coid_fnc_count ) { \\" EOL
"		if( (coid_flags[i] & COID_%name%_method_desc[i].flags & MethodDesc::xACCESS_MODE) ) \\" EOL
"			coid_fnc_table[t] = (coid_fnc) (tc) &%name%::M; \\" EOL
"		else *(void **) &coid_fnc_table[t] = (void *) coid_throw; \\" EOL
"	}" EOL
"" EOL
"" EOL
"#define COID_DISPATCH_CREATE_CALLER_HOOK(M,i,t) \\" EOL
"	if( i < coid_fnc_count ) { \\" EOL
"		if( (coid_flags[i] & COID_%name%_method_desc[i].flags & MethodDesc::xACCESS_MODE) ) \\" EOL
"			coid_fnc_table[t] = (coid_fnc) &DISPATCH_CALLER_%name%_%_version_%::M; \\" EOL
"		else *(void **) &coid_fnc_table[t] = (void *) coid_throw; \\" EOL
"	}" EOL
"" EOL
"" EOL
"" EOL
"" EOL
"" EOL
"$$$$" EOL
//"/// Service name, version:" EOL
//"static const char * COID_%name% = \"%name%\";" EOL
//"static const char * COID_short_%name% = \"%shortname%\";" EOL
//"static const char * COID_version_%name% = \"%version%\";" EOL
"" EOL
"/// functions:" EOL
"uint COID_%name%_%_version_%_get_method_id( const token & name );" EOL
"opcd COID_%name%_%_version_%_dispatch( InstanceData * _coid_inst_data, uint _coid_fnc_id, binstream& _coid_bstr, metastream* coid_meta=0 );" EOL
"metastream& COID_%name%_%_version_%_getmeta();" EOL
"" EOL
"" EOL
"" EOL
"struct DISPATCH_CALLER_%name%_%_version_%" EOL
"{" EOL
"	void call_dispatch( binstream * b ) {" EOL
"		COID_CLIENT_EXESTREAM_ARGS * a = (COID_CLIENT_EXESTREAM_ARGS *) this;" EOL
"		InstanceData d;  d._object = a->obj;" EOL
"		COID_%name%_%_version_%_dispatch( &d, a->id, *b );" EOL
"	}" EOL
"};" EOL
"" EOL
"" EOL
"$$$$" EOL  //tp_fnc_enum_start
"" EOL
"" EOL
"" EOL
"enum {	/// command ids, format is: COID_classname_fncname_fncid" EOL
"$$$$" EOL  //tp_fnc_enum_end
"    COID_%name%_accept_connect_5," EOL
"    COID_%name%_accept_connect_shared_6" EOL
"};" EOL
"" EOL
"" EOL
"" EOL
"/// info about every function:" EOL
"$$$$" EOL  //tp_fnc_info0
"" EOL
"" EOL
"/// create structure that holds everything about function:" EOL
//"%empty_method_set_start%"
"static const MethodDesc COID_%name%_method_desc[] = {" EOL
"$$$$" EOL  //tp_fnc_info_end
"};" EOL
//"%empty_method_set_end%"
"" EOL
"$$$$" EOL  //tp_descriptor0
"" EOL
"" EOL
"static const char * COID_dependencies_%name%[] = {" EOL
"%dependencies%" EOL
"	NULL" EOL
"};" EOL
"" EOL
"" EOL
"/// ServiceDescriptor:" EOL
"static ServiceDescriptor COID_descriptor_%name%;" EOL
"" EOL
"" EOL
"" EOL
"/// dispatch stores function tables for all 'direct' clients with different minor versions here" EOL
"class COID_register_%name%_%_version_%" EOL
"{" EOL
"	struct table {" EOL
"		uint ver;" EOL
"		coid_fnc * tbl;" EOL
"	};" EOL
"	dynarray<table>	_tables;" EOL
"" EOL
"public:" EOL
"//	comm_mutex_rw	_mx;" EOL
"	comm_mutex	_mx;" EOL
"   const void* (*dummyreg)();" EOL
"" EOL
"	COID_register_%name%_%_version_%() {" EOL
"		COID_descriptor_%name%._version.set( %comm_version% );" EOL
"		COID_descriptor_%name%._coid_version = %coid_version%;" EOL
"		COID_descriptor_%name%._name = \"%name%\";" EOL
"		COID_descriptor_%name%._shortname = \"%shortname%\";" EOL
"		COID_descriptor_%name%._info = \"%info%\";" EOL
"		COID_descriptor_%name%._dependencies = COID_dependencies_%name%;" EOL
"		COID_descriptor_%name%._nmeth = %fnc_max_count%;" EOL
"		COID_descriptor_%name%._methflags = %fnc_method_flags%;" EOL
"		COID_descriptor_%name%._flags = %flags%;" EOL
"		COID_descriptor_%name%._acceptor_port = (uint) %acceptor_port%;" EOL
"		COID_descriptor_%name%._bin_svc_data = COID_bin_data;" EOL
"		COID_descriptor_%name%.get_method_id = COID_%name%_%_version_%_get_method_id;" EOL
"		COID_descriptor_%name%.dispatch = COID_%name%_%_version_%_dispatch;" EOL
"		COID_descriptor_%name%._fnc_get_meta = COID_%name%_%_version_%_getmeta;" EOL
"#ifdef _DEBUG" EOL
"		COID_descriptor_%name%._flags |= ServiceDescriptor::fDEBUG;" EOL
"#endif" EOL
"		_mx.set_name( \"COID_register_%name%_%_version_%\" );" EOL
"		INTERFACE_REGISTER(ServiceDescriptor).add( &COID_descriptor_%name% );" EOL
"	}" EOL
"" EOL
"	~COID_register_%name%_%_version_%() {" EOL
"//		MXGUARDRW( (comm_mutex_rw &) _mx );" EOL
"		MXGUARD( (comm_mutex &) _mx );" EOL
"		for( uint i=0; i<_tables.size(); i++ )" EOL
"			delete [] _tables[i].tbl;" EOL
"	}" EOL
"	coid_fnc * get_table_notlocked( uint ver ) {" EOL
"		for( uint i=0; i<_tables.size(); i++ )" EOL
"			if( ver == _tables[i].ver ) return _tables[i].tbl;" EOL
"		return NULL;" EOL
"	}" EOL
"	coid_fnc * get_table( uint ver ) {" EOL
"//		MXGUARDRW( (const comm_mutex_rw &) _mx );		/// ==> read lock" EOL
"		MXGUARD( (const comm_mutex &) _mx );" EOL
"		return get_table_notlocked( ver );" EOL
"	}" EOL
"	void insert_table( uint ver, coid_fnc * tbl ) {" EOL
"		table * t = _tables.add( 1 );	/// mutex has been locked" EOL
"		t->ver = ver; t->tbl = tbl;" EOL
"	}" EOL
"};" EOL
"" EOL
"" EOL

"// for dll linking" EOL
"COID_register_%name%_%_version_% & get_COID_register_%name%_%_version_%()" EOL
"{" EOL
"	static COID_register_%name%_%_version_% x;" EOL
"	x.dummyreg = &COID_GET_FN;    //force exporting the symbol" EOL
"	x.dummyreg();" EOL
"	return x;" EOL
"}" EOL
"" EOL
"//for static linking (must be called from outside to link this object)" EOL
"void get_COID_register_%name%()" EOL
"{" EOL
"	COID_register_%name%_%_version_%();" EOL
"}" EOL
"" EOL
"static COID_register_%name%_%_version_% & COID_auto_register_variable = get_COID_register_%name%_%_version_%();" EOL
"" EOL
"" EOL

"$$$$" EOL  //tp_fnc_body0
"		case %fnc_id_name%: {" EOL
"$$$$" EOL  //tp_fnc_body
"			if( (_coid_inst_data->_flags & (MethodDesc::fLOG_CALL | MethodDesc::fLOG_DURATION)) == (MethodDesc::fLOG_CALL | MethodDesc::fLOG_DURATION) )" EOL
"				_coid_%name%_ticks = SINGLETON(HPTIMER).ftime();" EOL
"			%fnc_get_params%" EOL
"			if( _coid_inst_data->_flags & MethodDesc::fLOG_CALL ) {" EOL
"				_coid_log = &_coid_inst_data->_cmdin->post_method();" EOL
"				*_coid_log << %fnc_log%;" EOL
"			}" EOL
"" EOL
"			_coid_bstr.acknowledge();" EOL
"" EOL
"			%fnc_call%" EOL
"			%fnc_get_results%" EOL
"" EOL
"			if( _coid_inst_data->_flags & MethodDesc::fLOG_CALL ) {" EOL
"				*_coid_log << %fnc_log_output%;" EOL
"				if( _coid_inst_data->_flags & MethodDesc::fLOG_DURATION )" EOL
"					*_coid_log << \" [\" << (SINGLETON(HPTIMER).ftime() - _coid_%name%_ticks) * 1000 << \"]\";" EOL
"				if( !_coid_err_code ) *_coid_log << \" .. ok\" << EOM;" EOL
"				else *_coid_log << \" .. fail: \" << opcd_formatter(_coid_err_code) << EOM;" EOL
"			}" EOL
"			%fnc_delete_tmp_objects%" EOL
"$$$$" EOL  //tp_fnc_body2
"		} break;" EOL
"$$$$" EOL  //tp_getmeta
"" EOL
"" EOL
"" EOL
"metastream& COID_%name%_%_version_%_getmeta()" EOL
"{" EOL
"    static metastream* meta = 0;" EOL
"    if(meta)  return *meta;" EOL
"" EOL
"    meta = new metastream;" EOL
"#define META_TD(TY)     metastream::TypeDesc< TY >::get_str(*meta)" EOL
"" EOL
"$$$$" EOL  //tp_getmeta2
"" EOL
"    return *meta;" EOL
"}" EOL
"$$$$" EOL  //tp_getmeta_fn
"    {   //%fnc_id_name%" EOL
"        ServiceDescriptor::MethodDesc* med = (ServiceDescriptor::MethodDesc*)&COID_descriptor_%name%._methflags[%fnc_id_name%];" EOL
"        %fnc_get_params_meta%"
"$$$$" EOL  //tp_getmeta_fn2
"    }" EOL
"$$$$" EOL  //tp_getmeta_fn_noimpl_accept
"    {   //%fnc_id_name%" EOL
"        ServiceDescriptor::MethodDesc* med = (ServiceDescriptor::MethodDesc*)&COID_descriptor_%name%._methflags[COID_descriptor_%name%._nmeth];" EOL
"        med->retval.meta = META_TD(opcd);" EOL
"    }" EOL
"$$$$" EOL  //tp_getmeta_fn_noimpl_accept_shared
"    {   //%fnc_id_name%" EOL
"        ServiceDescriptor::MethodDesc* med = (ServiceDescriptor::MethodDesc*)&COID_descriptor_%name%._methflags[COID_descriptor_%name%._nmeth+1];" EOL
"        med->retval.meta = META_TD(opcd);" EOL
"    }" EOL
"$$$$" EOL  //tp_dispatch0
"" EOL
"" EOL
"" EOL
"///////////////////////////////////////////////////////////////////////////////" EOL
"opcd COID_%name%_%_version_%_dispatch( InstanceData* _coid_inst_data, uint _coid_fnc_id, binstream& _coid_bstr, metastream* coid_meta )" EOL
"{" EOL
"	%name% * _coid_%name%_obj = (%name% *) _coid_inst_data->_object;" EOL
"	double _coid_%name%_ticks = 0.0;" EOL
"	binstream * _coid_log = NULL;" EOL
"	opcd _coid_err_code = 0;" EOL
"" EOL
"	switch( _coid_fnc_id ) {" EOL
"		case StdDispatchMethod::CONSTRUCTOR: {" EOL
"			_coid_inst_data->_object = _coid_%name%_obj = new %name%;" EOL
"       } break;" EOL
"		case StdDispatchMethod::POSTCONSTRUCTOR: {" EOL
"$$$$" EOL
"		} break;" EOL
"		case StdDispatchMethod::DESTRUCTOR: {" EOL
"			delete _coid_%name%_obj; _coid_inst_data->_object = NULL;" EOL
"		} break;" EOL
"		case StdDispatchMethod::CREATE_INTERFACE: {" EOL
"$$$$" EOL
"		} break;" EOL
"		case StdDispatchMethod::AUTHENTIFY: {" EOL
"$$$$" EOL
"		} break;" EOL
"		case StdDispatchMethod::AUTHENTIFY_SHARED: {" EOL
"$$$$" EOL
"		} break;" EOL
"		case StdDispatchMethod::AUTHENTIFY_AUTO: {" EOL
"$$$$" EOL
"		} break;" EOL
"		case StdDispatchMethod::HANDLE_NET_LOOP: {" EOL
"$$$$" EOL
"		} break;" EOL
"		case StdDispatchMethod::PREDESTRUCTOR: {" EOL
"$$$$" EOL
"		} break;" EOL
"		case StdDispatchMethod::COMMAND: {" EOL
"$$$$" EOL
"		} break;" EOL
"		case StdDispatchMethod::SPAWN: {" EOL
"$$$$" EOL
"		} break;" EOL
"		case StdDispatchMethod::ECHO: {" EOL
"$$$$" EOL
"		} break;" EOL
"" EOL
"" EOL
"		/// service-specific methods:" EOL
"$$$$" EOL
"" EOL
"" EOL

"		default:" EOL
"			_coid_bstr.acknowledge( true );" EOL
"			_coid_bstr << ersNOT_IMPLEMENTED;" EOL
"			_coid_bstr.flush();" EOL
"			return ersNOT_IMPLEMENTED;" EOL
"		break;" EOL

"	}" EOL
"" EOL
"" EOL
"" EOL
"	return _coid_err_code;" EOL
"}" EOL
"" EOL
"" EOL
"" EOL
"" EOL
"" EOL
"" EOL
"" EOL
"$$$$" EOL
/// function not implemented
"			_coid_bstr.acknowledge();" EOL
"			_coid_bstr << _coid_err_code;" EOL
"			_coid_bstr.flush();" EOL
"			return ersNOT_IMPLEMENTED;" EOL
"$$$$" EOL
/// accept_connect() or accept_connect_shared() not implemented
"			_coid_bstr.acknowledge();" EOL
"			_coid_bstr << _coid_err_code;" EOL
"			return ersNOT_IMPLEMENTED;" EOL
"$$$$" EOL
/// create interface
"			int _coid_command_params_ptr;" EOL
"			_coid_bstr >> _coid_command_params_ptr;" EOL
"			_coid_bstr.acknowledge();" EOL
"			command_tokens * _coid_command_params = (command_tokens *) _coid_command_params_ptr;" EOL
"			_coid_err_code = _coid_%name%_obj->accept_command( *_coid_command_params );" EOL
"//			_coid_bstr << _coid_err_code;" EOL
"			_coid_bstr.flush();" EOL
"$$$$" EOL
"			CreateInterfaceInfo* coid_iface_info;" EOL
"			_coid_bstr.read_ptr(coid_iface_info);" EOL
"			const uint coid_fnc_count = coid_iface_info->_nmethods;" EOL
"%declare_coid_flags_if_nonzero%"
"			coid_fnc * coid_fnc_table = get_COID_register_%name%_%_version_%().get_table( coid_iface_info->_clientver.get_minor() );" EOL
"" EOL
"			if( !coid_fnc_table ) {" EOL
"				//MXGUARDRW( get_COID_register_%name%_%_version_%()._mx );" EOL
"				MXGUARD( get_COID_register_%name%_%_version_%()._mx );" EOL
"				coid_fnc_table = get_COID_register_%name%_%_version_%().get_table_notlocked( coid_iface_info->_clientver.get_minor() );" EOL
"				if( !coid_fnc_table ) {" EOL

// this line below does not work with M$ compiler
//"					coid_fnc_table = new coid_fnc[coid_fnc_count + 1];" EOL
"					coid_fnc_table = (coid_fnc *) new char[ sizeof(coid_fnc) * (coid_fnc_count + 1) ];	/// new coid_fnc[...] would allocate pointer to 0 bytes (M$ 'feature')" EOL

"					memset( coid_fnc_table, 0, (coid_fnc_count + 1) * sizeof(coid_fnc) );" EOL
"					uint coid_table_index = 0;" EOL
"" EOL
"					((CreateInterfaceInfo::t_fnc *) coid_fnc_table)[coid_table_index++] = coid_iface_info->_disconnect_interface;" EOL
"$$$$" EOL
"" EOL
"					get_COID_register_%name%_%_version_%().insert_table( coid_iface_info->_clientver.get_minor(), coid_fnc_table );" EOL
"				}" EOL
"			}" EOL
"" EOL
"			_coid_bstr.acknowledge();" EOL
"			_coid_bstr.write_ptr( coid_fnc_table );" EOL
"			_coid_bstr.write_ptr( _coid_inst_data->_object );" EOL
"			_coid_bstr.write_ptr( coid_iface_info->_mutex );" EOL

"$$$$" EOL

"" EOL
"" EOL
"" EOL
"" EOL
"" EOL
"/// method table" EOL
"%empty_method_set_start%"
"static METHOD_TABLE COID_%name%_method_table[] = {" EOL

"$$$$" EOL

"};" EOL
"" EOL
"" EOL

"$$$$" EOL

"" EOL
"#define COID_dispatch_method_size		(sizeof(COID_%name%_method_table) / sizeof(METHOD_TABLE))" EOL
"" EOL
"%empty_method_set_end%"
"" EOL
"" EOL
"uint COID_%name%_%_version_%_get_method_id( const token & name )" EOL
"{" EOL
"%empty_method_set_start%"
"	hash<token> mha;" EOL
"	uints idx = mha(name) % COID_dispatch_method_size;" EOL
"" EOL
"	for( uints i=0; i<COID_dispatch_method_size; i++ ) {" EOL
"		if( COID_%name%_method_table[idx].name )" EOL
"			if( name == COID_%name%_method_table[idx].name )" EOL
"				return COID_%name%_method_table[idx].id;" EOL
"		idx++;" EOL
"		if( idx == COID_dispatch_method_size ) idx = 0;" EOL
"	}" EOL
"%empty_method_set_end%"
"" EOL
"	return UMAX32;" EOL
"}" EOL
"" EOL
"" EOL
"} // namespace %namespace%" EOL

"$$$$" EOL		/// accept_net_connections

"			uint port;" EOL
"			netSocket* s;" EOL
"			_coid_bstr.read_ptr(s);" EOL
"			_coid_bstr >> port;" EOL
"			_coid_bstr.acknowledge();" EOL
"			opcd e = _coid_%name%_obj->accept_net_connections( s, port );" EOL
"			_coid_bstr << e;" EOL
"			_coid_bstr.flush();" EOL
"			return e;" EOL
;






/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////



char TEMPL_CLIENT_IN_CPP[] =
"   %name%_localclient( netstream * b, binstream * b2 ) : cc(b, b2) {}" EOL
"   void coid_throw();" EOL
"   opcd disconnect() { return cc.disconnect(); }" EOL
EOL
EOL
;




char TEMPL_CLIENT_H[] =
"private:" EOL
"	COID_TABLE_%name%_%_version_% * _me;" EOL
"	COID_TABLE_%name%_%_version_% * _vtbl;" EOL
"	mutable comm_mutex_custom_reg<netstream, void*> _mx_reg;" EOL
"%mexestream%"
"	uint _conn_data;" EOL
"	uint _timeout;" EOL
"	charstr _addr;" EOL
EOL
"	void set_connection_type( uint ct ) {_conn_data = ct;}" EOL
"	void destroy_me();" EOL
EOL
"public:" EOL
"	%name%_client();" EOL
"	~%name%_client();" EOL

/// copy constructor, operator =
"	%name%_client( const %name%_client & c );" EOL
"	%name%_client & operator = ( const %name%_client & c );" EOL
EOL
"	opcd ping_server( const char * coid_address, uint coid_obj_id=UMAX32, uint coid_flags=ConnectFlags::xACCESS_MODE ) const;"
EOL
"	bool is_connected() const;" EOL
"	opcd disconnect();" EOL
"	const charstr& get_addr() const {return _addr;}" EOL
"	comm_mutex_reg * get_mx() {return &_mx_reg;}" EOL
"	opcd get_last_error() const;" EOL
"	void set_last_error( opcd e );" EOL
"	uint get_connection_type() const {return _conn_data;}" EOL
"	opcd set_timeout( uint milliseconds );" EOL
"	uint get_timeout() const {return _timeout;}" EOL
"	void setup_stream( binstream& b, uint coid_flags, uint coid_obj_id ) const;" EOL
"	bool setup_members( uint coid_stream_flags, netstream * bstream, binstream * bstream2=NULL, comm_mutex_reg * mx_reg=NULL );" EOL
EOL
"	static const version & get_version() { return COID_version_%name%_%_version_%; }" EOL
EOL
EOL

"$$$$" EOL

"#include \"coid/coidclient.h\"" EOL
"#include \"coid/comm/sync/mutex_reg.h\"" EOL
EOL
EOL
"extern const version COID_version_%name%_%_version_%;" EOL
EOL
EOL
;




/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////





char TEMPL_CLIENT_CPP[] =

	// tp_includes

"#include \"%client_header_name%\"" EOL
"#include \"coid/comm/binstream/container_linear.h\"" EOL
EOL
EOL
EOL
EOL
"namespace %namespace% {" EOL
EOL
"%fnc_client_table%"
EOL
EOL
"}	// namespace %namespace%" EOL
EOL
EOL
EOL
"#define ___COID_CONNECTWITHIN_TRY		try {" EOL
"#define ___COID_CONNECTWITHIN_CATCH	} catch( opcd ___coid_err ) {return ___coid_err;}\\" EOL
"										catch(...) { return ersFE_EXCEPTION \"client method exception\"; }" EOL
"#define ___COID_CONNECT_TRY		try {" EOL
"#define ___COID_CONNECT_CATCH		} catch( opcd ___coid_err ) {delete _coid_bstream; return ___coid_err;}\\" EOL
"									catch( ThreadException & ) { delete _coid_bstream; throw; }\\" EOL
"									catch(...) { delete _coid_bstream; return ersFE_EXCEPTION \"client method exception\"; }" EOL
EOL
EOL
EOL

"$$$$" EOL

	// tp_static

EOL
EOL
"const version COID_version_%name%_%_version_%( %comm_version% );" EOL
EOL
"static COID_NICK g_coid_nick;" EOL
EOL
"namespace %namespace% {" EOL
EOL
"static COID_TABLE_%name%_%_version_% * coid_interprocess_vtbl = NULL;" EOL
"static COID_TABLE_%name%_%_version_% * coid_remote_vtbl = NULL;" EOL
"static comm_mutex coid_table_mx( true, \"COID_TABLE_%name%_%_version_%\" );" EOL
EOL
"struct TABLE_REMOVER_%name%_%_version_% {" EOL
"	~TABLE_REMOVER_%name%_%_version_%() {delete coid_interprocess_vtbl; delete coid_remote_vtbl;}" EOL
"};" EOL
"static TABLE_REMOVER_%name%_%_version_%	%name%_%_version_%_table_trash;" EOL
EOL
EOL
EOL

"$$$$" EOL

	// tp_fnc_enum

EOL
EOL
"enum {	/// command ids, format is: COID_classname_fncname_fncid" EOL

"$$$$" EOL

	// tp_fnc_flags

"};" EOL
EOL
EOL
EOL
EOL
"static uint COID_method_flags_%name%[%method_flags_max_count%] = {" EOL

"$$$$" EOL

	// tp_fnc_flags_end

EOL
"};" EOL
EOL
EOL
EOL
EOL
"/***************************************************************************" EOL
"%name%_localclient" EOL
"***************************************************************************/"
EOL

"$$$$" EOL

	// tp_fnc_defines

EOL
EOL
"/// fake function:" EOL
"void %name%_localclient::coid_throw() {throw ersFE_EXCEPTION;}" EOL
EOL
EOL
"typedef void (%name%_localclient::*coid_fnc)();" EOL
EOL
"#define COID_CLIENT_CREATE_HOOK(M,i,t,tc)\\" EOL
"	if( COID_method_flags_%name%[i] & coid_stream_flags ) ((coid_fnc *) table)[t] = (coid_fnc) (tc) &%name%_localclient::M;\\" EOL
"	else ((coid_fnc *) table)[t] = (coid_fnc) &%name%_localclient::coid_throw;" EOL
EOL

"#define COID_CLIENT_CREATE_DISCONNECT_HOOK(t)\\" EOL
"	((coid_fnc *) table)[t] = (coid_fnc) &%name%_localclient::disconnect;" EOL


EOL

"$$$$" EOL

	// tp_init_table

EOL
EOL
EOL
EOL
"void inline %name%_localclient::coid_init_table( uint coid_stream_flags, COID_TABLE_%name%_%_version_% *& table )" EOL
"{" EOL
"	table = new COID_TABLE_%name%_%_version_%;" EOL
//"//	memset( table, 0, sizeof(COID_TABLE_%name%_%_version_%) );" EOL
EOL
"	uint coid_table_index = 0;" EOL

"$$$$" EOL

	// tp_init_table_end

"}" EOL
EOL
EOL
EOL
EOL



"$$$$" EOL

	// tp_fnc_body

EOL
EOL
"%fnc_client_body%" EOL

"$$$$" EOL

	// tp_fnc_body0

"	%fnc_client_retval_declaration%" EOL
"	*_coid_bstream << (uint) %fnc_id_name%;" EOL
"	*_coid_bstream << _coid_inst_id;" EOL

"$$$$" EOL

	// tp_fnc_body1

EOL
"	_coid_bstream->flush();" EOL
"	_coid_err_code = _coid_bstream->get_error();" EOL
"	if( _coid_err_code ) {" EOL
"		%fnc_client_set_error_ret_value%" EOL
"		_coid_bstream->acknowledge();" EOL
"		%fnc_client_return%" EOL
"	}" EOL

"$$$$" EOL

	// tp_fnc_body2

EOL
"	_coid_bstream->acknowledge();" EOL
EOL
"	%fnc_client_return%" EOL
"}" EOL


"$$$$" EOL

	// tp_fnc_body0_cc

"	%fnc_client_retval_declaration%" EOL
"	*cc._coid_bstream << (uint) %fnc_id_name%;" EOL
"	*cc._coid_bstream << cc._coid_inst_id;" EOL

"$$$$" EOL

	// tp_fnc_body1_cc

EOL
"	cc._coid_bstream->flush();" EOL
"	cc._coid_err_code = cc._coid_bstream->get_error();" EOL
"	if( cc._coid_err_code ) {" EOL
"		%fnc_client_set_error_ret_value%" EOL
"		cc._coid_bstream->acknowledge();" EOL
"		%fnc_client_return_cc%" EOL
"	}" EOL

"$$$$" EOL

	// tp_fnc_body2_cc

EOL
"	cc._coid_bstream->acknowledge();" EOL
EOL
"	%fnc_client_return_cc%" EOL
"}" EOL

"$$$$" EOL

	// tp_accept_connect_within

EOL
EOL
EOL
EOL
EOL
"%fnc_client_body%" EOL
EOL
EOL

"$$$$" EOL

	// tp_accept_connect

EOL
EOL
EOL
EOL
EOL
"%fnc_client_body%" EOL
EOL
EOL

"$$$$" EOL

	// tp_accept_connect_shared

EOL
EOL
EOL
"%fnc_client_body%" EOL
EOL
EOL
EOL
EOL
EOL

"$$$$" EOL

	// tp_fnc_connect_within0

"	if( !coid_channel.is_set() ) return ersFE_CHANNEL;" EOL
"	_addr.reset();" EOL
"	extendedGUARD_reg __coid__mxg( coid_channel, true );" EOL
EOL
"	netstream * _coid_bstream = (netstream *) ((comm_mutex_custom_reg<netstream, void*> &) coid_channel)._p1;" EOL
"	if( !_coid_bstream ) return ersFE_UNREACHABLE;" EOL
"	/// we must avoid direct access mode" EOL
"	setup_stream( *_coid_bstream, ConnectFlags::fACCESS_MODE_REMOTE | ConnectFlags::fACCESS_MODE_INTERPROCESS | ConnectFlags::fWITHIN_CHANNEL, UMAX32 );" EOL
"	___COID_CONNECTWITHIN_TRY" EOL

"$$$$" EOL

	// tp_fnc_connect_within1

EOL
"	_coid_bstream->flush();" EOL
"	opcd _coid_err_code = _coid_bstream->get_error();" EOL
"	if( _coid_err_code ) {" EOL
"		_coid_bstream->acknowledge();" EOL
"		return _coid_err_code;" EOL
"	}" EOL

"$$$$" EOL

	// tp_fnc_connect_within2

EOL
"	uint coid_stream_flags;" EOL
"	*_coid_bstream >> coid_stream_flags;" EOL
"	RASSERT( coid_stream_flags & ConnectFlags::xACCESS_MODE );" EOL
"	setup_members( coid_stream_flags, _coid_bstream, _coid_bstream, &coid_channel );" EOL
EOL
"	return _coid_err_code;" EOL
EOL
"	___COID_CONNECTWITHIN_CATCH" EOL
"}" EOL

"$$$$" EOL

	// tp_fnc_connect_body0  (connect / connect_shared)

"	disconnect();" EOL
"	_addr.reset();" EOL
"	extendedGUARD_reg __coid__mxg( _mx_reg, false );" EOL
"	if( _mx_reg.is_valid() ) {" EOL
"		if( get_connection_type() == ConnectFlags::fACCESS_MODE_DIRECT ) {	/// direct" EOL
"			return ersFE_ALREADY_CONNECTED;" EOL
"		}" EOL
"		else if( get_connection_type() == ConnectFlags::fACCESS_MODE_INTERPROCESS ) {	/// interprocess" EOL
"			__coid__mxg.lock();" EOL
"			if( ((COID_CLIENT *)_me)->is_stream_open() )" EOL
"				return ersFE_ALREADY_CONNECTED;" EOL
"		}" EOL
"		else if( get_connection_type() == ConnectFlags::fACCESS_MODE_REMOTE ) {	/// remote" EOL
"			__coid__mxg.lock();" EOL
"			if( ((COID_CLIENT *)_me)->is_stream_open() )" EOL
"				return ersFE_ALREADY_CONNECTED;" EOL
"		}" EOL
"	}" EOL
EOL
"	netstream * _coid_bstream = COID_CLIENT::create_stream( \"%name%\", coid_address, _addr, (coid_flags & ConnectFlags::fTUNNEL) != 0 );" EOL
"	if( !_coid_bstream ) return ersFE_UNREACHABLE;" EOL
"	if( _timeout ) _coid_bstream->set_timeout( _timeout );" EOL
"	coid_flags &= ~ConnectFlags::fTUNNEL;" EOL

"	setup_stream( *_coid_bstream, coid_flags, %fnc_client_shared_params% );" EOL
"	___COID_CONNECT_TRY" EOL

"$$$$" EOL

	// tp_fnc_connect_body1

EOL
"	_coid_bstream->flush();" EOL
"	opcd _coid_err_code = _coid_bstream->get_error();" EOL
"	if( _coid_err_code ) {" EOL
"		_coid_bstream->acknowledge(true);" EOL
"		delete _coid_bstream;" EOL
"		return _coid_err_code;" EOL
"	}" EOL

"$$$$" EOL

	// tp_fnc_connect_body2

EOL
"	uint coid_stream_flags;" EOL
"	*_coid_bstream >> coid_stream_flags;" EOL
"	RASSERT( coid_stream_flags & ConnectFlags::xACCESS_MODE );" EOL
"	setup_members( coid_stream_flags, _coid_bstream, _coid_bstream );" EOL
EOL
"	return _coid_err_code;" EOL
EOL
"	___COID_CONNECT_CATCH" EOL
"}" EOL

"$$$$" EOL

	// tp_x_client

EOL
EOL
EOL
"/***************************************************************************" EOL
"%name%_client" EOL
"***************************************************************************/"
EOL
EOL

"%name%_client::%name%_client() : _me(NULL), _vtbl(NULL), _conn_data(0), _timeout(0)" EOL
"{" EOL
"	netSubsystem::instance();" EOL
"}" EOL
"%name%_client::~%name%_client()" EOL
"{" EOL
"	disconnect();" EOL
"}" EOL

/// copy constructor, operator =
"%name%_client::%name%_client( const %name%_client & c ) {throw ersFE_EXCEPTION;}" EOL
"%name%_client & %name%_client::operator = ( const %name%_client & c ) {throw ersFE_EXCEPTION; return *this;}" EOL

EOL
"void %name%_client::destroy_me()" EOL
"{" EOL
"	if( get_connection_type() != ConnectFlags::fACCESS_MODE_DIRECT )" EOL
"		delete (%name%_localclient *) _me;" EOL
"	_me = NULL;" EOL
"}" EOL
EOL
"opcd %name%_client::disconnect()" EOL
"{" EOL
"	if(!_me)" EOL
"		return 0;" EOL
"	DASSERT( _mx_reg.is_valid() );" EOL
"	comm_mutex & lowlevelmx = _mx_reg._mxc->_mx;" EOL
"	bool last = false;" EOL
"	opcd coid_err;" EOL
"	try {" EOL
"		extendedGUARD_lock( _mx_reg );" EOL
"		DASSERT( _me );" EOL
"		coid_err = ((get_connection_type() == ConnectFlags::fACCESS_MODE_DIRECT ? (COID_TABLE_%name%_%_version_% *) this : _me)->*(_vtbl->disconnect)) ();" EOL
"		destroy_me();" EOL
"		if( _mx_reg.counter_fast() == 1 ) {" EOL
"			_mx_reg.disable_fast();" EOL
"			lowlevelmx.unlock();" EOL
"			__coid__mxg.eject();" EOL
"			last = true;" EOL
"		}" EOL
"	}" EOL
"	catch( opcd e ) {" EOL
"		destroy_me(); coid_err = e;" EOL
"	}" EOL
EOL
"	if( last ) {" EOL
"#ifdef _DEBUG" EOL
"		const int max = 0xFFFF;" EOL
"#else" EOL
"		const int max = 10;" EOL
"#endif" EOL
"		int i=0;" EOL
"		for( ; i<max; i++ ) {" EOL
"			if( lowlevelmx.try_lock() ) {lowlevelmx.unlock(); break;}" EOL
"			sysMilliSecondSleep( 10 );" EOL
"		}" EOL
"		if( i == max ) throw ersFE_EXCEPTION;" EOL
"	}" EOL
EOL
"	_mx_reg.destroy_all();" EOL
"	_vtbl = NULL;" EOL
"	set_connection_type( 0 );" EOL
"	return coid_err;" EOL
"}" EOL
EOL
"bool %name%_client::is_connected() const" EOL
"{" EOL
"    return _me != NULL" EOL
"        && ((get_connection_type() & ConnectFlags::fACCESS_MODE_DIRECT)!=0  ||  ((netstream*)_mx_reg._p1)->is_socket_connected());" EOL
"}" EOL
EOL
"opcd %name%_client::get_last_error() const" EOL
"{" EOL
"	if( !is_connected() ) return 0;" EOL
"	if( get_connection_type() == ConnectFlags::fACCESS_MODE_REMOTE ) return ((COID_CLIENT *) _me)->get_last_error();" EOL
"	else if( get_connection_type() == ConnectFlags::fACCESS_MODE_INTERPROCESS ) return ((COID_CLIENT *) _me)->get_last_error();" EOL
"	return 0;" EOL
"}" EOL
EOL
"void %name%_client::set_last_error( opcd e )" EOL
"{" EOL
"	if( !is_connected() ) return;" EOL
"	if( get_connection_type() == ConnectFlags::fACCESS_MODE_REMOTE ) ((COID_CLIENT *) _me)->set_last_error( e );" EOL
"	else if( get_connection_type() == ConnectFlags::fACCESS_MODE_INTERPROCESS ) ((COID_CLIENT *) _me)->set_last_error( e );" EOL
"}" EOL


EOL
"inline bool %name%_client::setup_members( uint coid_stream_flags, netstream * bstream, binstream * bstream2, comm_mutex_reg * mx_reg )" EOL
"{" EOL
//"	disconnect();" EOL
"	set_connection_type( coid_stream_flags );" EOL
EOL
"	if( coid_stream_flags == ConnectFlags::fACCESS_MODE_DIRECT ) {	/// direct" EOL
"		if( !bstream2 ) bstream2 = bstream;" EOL
"		bstream2->read_ptr(_vtbl);" EOL
"		bstream2->read_ptr(_me);" EOL
"		comm_mutex_reg::refmutex* _rmx;" EOL
"		bstream2->read_ptr(_rmx);" EOL
"		_mx_reg.init( *_rmx );" EOL
"		bstream2->acknowledge();" EOL
"		delete bstream;" EOL
"	}" EOL
"	else if( coid_stream_flags == ConnectFlags::fACCESS_MODE_INTERPROCESS ) {	/// interprocess" EOL
"		if( !bstream2 ) bstream2 = bstream;" EOL
"		if( coid_interprocess_vtbl ) _vtbl = coid_interprocess_vtbl;" EOL
"		else {" EOL
"			MXGUARD( coid_table_mx );" EOL
"			if( !coid_interprocess_vtbl )" EOL
"				%name%_localclient::coid_init_table( coid_stream_flags, coid_interprocess_vtbl );" EOL
"			_vtbl = coid_interprocess_vtbl;" EOL
"		}" EOL
"		_me = (COID_TABLE_%name%_%_version_% *) new %name%_localclient( bstream, bstream2 );" EOL
"		bstream2->acknowledge();" EOL
"		_mx_reg.init( mx_reg, true, \"%name%_client\" );" EOL
"		_mx_reg._p1 = bstream;" EOL
"	}" EOL
"	else if( coid_stream_flags == ConnectFlags::fACCESS_MODE_REMOTE ) {	/// remote" EOL
"		if( !bstream2 ) bstream2 = bstream;" EOL
"		if( coid_remote_vtbl ) _vtbl = coid_remote_vtbl;" EOL
"		else {" EOL
"			MXGUARD( coid_table_mx );" EOL
"			if( !coid_remote_vtbl )" EOL
"				%name%_localclient::coid_init_table( coid_stream_flags, coid_remote_vtbl );" EOL
"			_vtbl = coid_remote_vtbl;" EOL
"		}" EOL
"		_me = (COID_TABLE_%name%_%_version_% *) new %name%_localclient( bstream, bstream2 );" EOL
"		bstream2->acknowledge();" EOL
"		_mx_reg.init( mx_reg, true, \"%name%_client\" );" EOL
"		_mx_reg._p1 = bstream;" EOL
"	}" EOL
"	else throw ersFE_EXCEPTION;" EOL
EOL
"	return true;" EOL
"}" EOL
EOL

"void %name%_client::setup_stream( binstream& b, uint coid_flags, uint coid_obj_id ) const" EOL
"{" EOL
"	if( coid_flags & ConnectFlags::fWITHIN_CHANNEL ) {" EOL
"		coid_flags &= ~ConnectFlags::fWITHIN_CHANNEL;" EOL
"		b << StdProtocolMethod::CONNECT;" EOL
"	}" EOL
"	uchar conchar = StdProtocolMethod::CONNECT_CHAR;" EOL
"	b << conchar << version(COID_VERSION);" EOL
"	b << g_coid_nick << coid_flags << COID_version_%name%_%_version_% << \"%name%\";" EOL
"	b << (uint) %fnc_max_count%;" EOL
"   b.write_ptr(COID_method_flags_%name%);" EOL
"   b << coid_obj_id << sysGetPid();" EOL
"   b.write_ptr(this);" EOL
"}" EOL

EOL

"opcd %name%_client::ping_server( const char * coid_address, uint coid_obj_id, uint coid_flags ) const" EOL
"{" EOL
"	coid_flags |= ConnectFlags::fPING_SERVER;" EOL
"	charstr tmp;" EOL
"	netstream * _coid_bstream = COID_CLIENT::create_stream( \"%name%\", coid_address, tmp, (coid_flags & ConnectFlags::fTUNNEL) != 0 );" EOL
"	if( !_coid_bstream ) return ersFE_UNREACHABLE;" EOL
"	if( _timeout ) _coid_bstream->set_timeout( _timeout );" EOL
"	coid_flags &= ~ConnectFlags::fTUNNEL;" EOL
"	setup_stream( *_coid_bstream, coid_flags, coid_obj_id );" EOL
"	___COID_CONNECT_TRY" EOL
"	_coid_bstream->flush();" EOL
"	opcd _coid_err_code = _coid_bstream->get_error();" EOL
"	_coid_bstream->acknowledge();" EOL
"	delete _coid_bstream;" EOL
"	return _coid_err_code;" EOL
EOL
"	___COID_CONNECT_CATCH" EOL
"}" EOL

EOL

"opcd %name%_client::set_timeout( uint milliseconds )" EOL
"{" EOL
"	if( milliseconds == _timeout ) return 0;" EOL
"	_timeout = milliseconds;" EOL
"	if( !is_connected() ) return 0;" EOL
"	if( get_connection_type() == ConnectFlags::fACCESS_MODE_DIRECT ) return 0;" EOL
"	netstream * n = ((COID_CLIENT *) _me)->get_stream();" EOL
"	if( !n ) return ersFAILED;" EOL
"	return n->set_timeout( _timeout );" EOL
"}" EOL

EOL
EOL
EOL

"$$$$" EOL

/// end of file
EOL
EOL
"}	/// namespace %namespace%" EOL
"$$$$" EOL
;





/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////



char TEMPL_OPEN_SVC_INIT[] =
"\t\tCOID_OPEN_SERVICE %open_service_arg_name%( true, _conn_data );" EOL
"\t\t%open_service_client_name%.setup_stream( %open_service_arg_name%.bw, _conn_data, UMAX32 );" EOL
;



char TEMPL_OPEN_SVC_SETUP[] =
"\t\tif( !_coid_err_code ) {" EOL
"\t\t\tnetstream * __coid_ns = NULL;" EOL
"\t\t\tif( get_connection_type() != ConnectFlags::fACCESS_MODE_DIRECT )" EOL
"\t\t\t\t__coid_ns = ((COID_CLIENT *) _me)->get_stream();" EOL
"\t\t\topcd __coid_err2;" EOL
"\t\t\t%open_service_arg_name%.br >> __coid_err2;" EOL
"\t\t\tif( !__coid_err2 ) {" EOL
"\t\t\t\tuint __coid_flags;" EOL
"\t\t\t\t%open_service_arg_name%.br >> __coid_flags;" EOL
"\t\t\t\tDASSERT( __coid_flags & ConnectFlags::xACCESS_MODE );" EOL
"\t\t\t\tDASSERT( __coid_flags == _conn_data );" EOL
"\t\t\t\t%open_service_client_name%.setup_members( __coid_flags, __coid_ns, &%open_service_arg_name%.br, &_mx_reg );" EOL
"\t\t\t}" EOL
"\t\t\telse if( !_coid_err_code ) _coid_err_code = __coid_err2;" EOL
"\t\t}" EOL
;




char TEMPL_INLINE_FNC[] =
"#ifndef %name%_NOTHROW" EOL
"\ttry {" EOL
"#endif" EOL
"\t\textendedGUARD_lock( _mx_reg );" EOL
"\t\tif( !_me ) %fnc_client_return_error%" EOL
"%ib_open_service1%"
"%ib_method_call%"
"%ib_open_service2%"
"#ifndef %name%_NOTHROW" EOL
"\t}" EOL
"\tcatch( opcd e ) {"
	/// continues in FUNCTION::stream_body_to()
;

char TEMPL_INLINE_FNC_NOLOCK[] =
"#ifndef %name%_NOTHROW" EOL
"\ttry {" EOL
"#endif" EOL
"\t\tif( !_me ) %fnc_client_return_error%" EOL
"%ib_open_service1%"
"%ib_method_call%"
"%ib_open_service2%"
"#ifndef %name%_NOTHROW" EOL
"\t}" EOL
"\tcatch( opcd e ) {"
	/// continues in FUNCTION::stream_body_to()
;



/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////




char TEMPL_MAKEFILE[] =
"DEST = $(shell coid-config -d)/%name%.dev" EOL
//"DEST = ../../bin/device/%name%/%name%.dev" EOL
"SRC = *.cpp" EOL
"INCLUDE = -I$(shell coid-config -i)" EOL
"LIBS = $(shell coid-config -l)/comm.a" EOL
//"INCLUDE = -I../../.." EOL
//"LIBS = ../../comm/comm.a" EOL
"STDLIBS = -lpthread" EOL
"IS_LIB = 0" EOL
"IS_SHARED_LIB = 1" EOL
"" EOL
"" EOL
"SRC2 = $(shell ls $(SRC))" EOL
"OBJS = $(SRC2:.cpp=.o)" EOL
"" EOL
"" EOL
"IS_DEBUG = $(shell test -f \".debug\" && echo 1)" EOL
"ifeq ($(IS_DEBUG), 1)" EOL
"	CC = g++ -Wall -g -fmessage-length=0" EOL
"else" EOL
"	CC = g++ -Wall -DNDEBUG -O3" EOL
"endif" EOL
"ifeq ($(IS_SHARED_LIB), 1)" EOL
"	CC += -fPIC" EOL
"endif" EOL
"" EOL
"" EOL
"params:" EOL
" @echo DEST = $(DEST)" EOL
" @echo INCLUDE = $(INCLUDE)" EOL
" @echo LIBS = $(LIBS)" EOL
" @echo SRC2 = $(SRC2)" EOL
"" EOL
"all: DELETE_DEPEND2 params $(DEST) SUCCESS" EOL
" #@echo DEST = $(DEST)" EOL
"" EOL
".PHONY: all" EOL
//"all: DELETE_DEPEND2 $(DEST) SUCCESS" EOL
//"" EOL
"" EOL
".cpp.o:" EOL
"	@echo $(<F)" EOL
"	@$(CC) -c $(INCLUDE) $(@D)/$(<F) -o $(@D)/$(@F)" EOL
"" EOL
"" EOL
"$(DEST): $(OBJS)" EOL
//"$(DEST): $(LIBS) $(OBJS)" EOL
"	@echo Linking ..." EOL
"	@mkdir -p $(@D)" EOL
"  ifeq ($(IS_LIB), 1)" EOL
"		@rm -f $(DEST)" EOL
"		@$(AR) $(ARFLAGS) $(DEST) $(OBJS) > /dev/null" EOL
"  else" EOL
"    ifeq ($(IS_SHARED_LIB), 1)" EOL
"		@$(CC) -shared -o $(DEST) $(OBJS) $(LIBS) $(STDLIBS)" EOL
"    else" EOL
"		@$(CC) -o $(DEST) $(OBJS) $(LIBS) $(STDLIBS)" EOL
"    endif" EOL
"    ifneq ($(IS_DEBUG), 1)" EOL
"		@strip $(DEST)" EOL
"    endif" EOL
"  endif" EOL
"" EOL
"" EOL
//"$(LIBS): FORCE" EOL
//"	@make -C $(@D)" EOL
"" EOL
"clean: DELETE_DEPEND2" EOL
"	@rm $(OBJS) $(DEST) 2> /dev/null || true" EOL
"" EOL
"cleanall: clean" EOL
"	@rm .depend .depen2 2> /dev/null || true" EOL
"	@for i in $(LIBS) ; do TMP=\"$${i%/*}\"; make -C $$TMP clean || true; done" EOL
"	@echo Ok" EOL
"" EOL
".DEFAULT: DELETE_DEPEND2" EOL
"	@echo No rule to make target $@" EOL
"" EOL
"DELETE_DEPEND2:" EOL
"	@rm .depend2 2>/dev/null || true" EOL
"" EOL
"FORCE:" EOL
"" EOL
"SUCCESS:" EOL
"	@echo Ok" EOL
"" EOL
"dep:" EOL
"	@if ! [ -f \".depend2\" ]; then \\" EOL
"		echo Building dependencies for $(DEST)  ...; \\" EOL
"		$(CC) -MM -c $(INCLUDE) $(SRC2) | sed \"s@^\\(\\(.*\\).o: \\(.*\\)\\2\\.cpp\\)@\\3\\1@\" > .depend; \\" EOL
"		echo Ok; \\" EOL
"	else \\" EOL
"		rm .depend2; \\" EOL
"	fi" EOL
"" EOL
".depend:" EOL
"	@echo Building dependencies for $(DEST)  ..." EOL
"	@$(CC) -MM -c $(INCLUDE) $(SRC2) | sed \"s@^\\(\\(.*\\).o: \\(.*\\)\\2\\.cpp\\)@\\3\\1@\" > .depend" EOL
"	@touch .depend2" EOL
"	@echo Ok" EOL
"" EOL
"-include .depend" EOL
"" EOL
"" EOL
;



